// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com

// ReSharper disable CheckNamespace
// ReSharper disable CommentTypo
// ReSharper disable IdentifierTypo
// ReSharper disable StringLiteralTypo

/* BindingSpecification.cs -- спецификация подшивки
 * Ars Magna project, http://arsmagna.ru
 */

#region Using directives

using System.ComponentModel;
using System.Diagnostics.Contracts;
using System.Text.Json.Serialization;
using System.Xml.Serialization;

using AM;

#endregion

#nullable enable

namespace ManagedIrbis.Magazines;

/// <summary>
/// Спецификация подшивки газет/журналов.
/// </summary>
public sealed class BindingSpecification
    : IVerifiable
{
    #region Properties

    /// <summary>
    /// Шифр журнала.
    /// </summary>
    /// <remarks>
    /// Например, "Л680583".
    /// </remarks>
    [JsonPropertyName ("magazine")]
    [XmlAttribute ("magazine")]
    [DisplayName ("Шифр журнала")]
    [Description ("Шифр журнала (обязательно)")]
    public string? MagazineIndex { get; set; }

    /// <summary>
    /// Год.
    /// </summary>
    /// <remarks>
    /// Например, "2017".
    /// </remarks>
    [JsonPropertyName ("year")]
    [XmlAttribute ("year")]
    [DisplayName ("Год")]
    [Description ("Год (обязательно)")]
    public string? Year { get; set; }

    /// <summary>
    /// Номер тома.
    /// </summary>
    /// <remarks>
    /// Например, "123".
    /// </remarks>
    [JsonPropertyName ("volume")]
    [XmlAttribute ("volume")]
    [DisplayName ("Том")]
    [Description ("Номер тома (необязательно)")]
    public string? VolumeNumber { get; set; }

    /// <summary>
    /// Номера выпусков.
    /// </summary>
    /// <remarks>
    /// Например, "1-27,29-58,60-72".
    /// </remarks>
    [JsonPropertyName ("numbers")]
    [XmlAttribute ("numbers")]
    [DisplayName ("Номера")]
    [Description ("Номера выпусков (обязательно)")]
    public string? IssueNumbers { get; set; }

    /// <summary>
    /// Описание.
    /// </summary>
    /// <remarks>
    /// Например, "янв.-июнь"
    /// </remarks>
    [JsonPropertyName ("description")]
    [XmlAttribute ("description")]
    [DisplayName ("Описание")]
    [Description ("Описание подшивки (необязательно)")]
    public string? Description { get; set; }

    /// <summary>
    /// Номер подшивки в году.
    /// </summary>
    /// <remarks>
    /// Например, "6284".
    /// </remarks>
    [JsonPropertyName ("number")]
    [XmlAttribute ("number")]
    [DisplayName ("Номер подшивки")]
    [Description ("Номер подшивки в году (обязательно)")]
    public string? BindingNumber { get; set; }

    /// <summary>
    /// Инвентарный номер подшивки.
    /// </summary>
    /// <remarks>
    /// Например, "Г6284".
    /// </remarks>
    [JsonPropertyName ("inventory")]
    [XmlAttribute ("inventory")]
    [DisplayName ("Инвентарный номер")]
    [Description ("Инвентарный номер подшивки (обязательно)")]
    public string? Inventory { get; set; }

    /// <summary>
    /// Место хранения подшивки.
    /// </summary>
    /// <remarks>
    /// Например, "ФП".
    /// </remarks>
    [JsonPropertyName ("place")]
    [XmlAttribute ("place")]
    [DisplayName ("Место хранения")]
    [Description ("Место хранения подшивки (обязательно)")]
    public string? Place { get; set; }

    /// <summary>
    /// Номер комплекта.
    /// </summary>
    /// <remarks>
    /// Например, "1".
    /// </remarks>
    [JsonPropertyName ("complect")]
    [XmlAttribute ("complect")]
    [DisplayName ("Номер комплекта")]
    [Description ("Номер комплекта (обязательно)")]
    public string? Complect { get; set; }

    /// <summary>
    /// Номера за другие годы.
    /// </summary>
    [Browsable (false)]
    [JsonPropertyName ("additional")]
    [XmlElement ("additional")]
    public YearVolumeNumbers[]? AdditionalYears { get; set; }

    /// <summary>
    /// Штрих-код или радиометка подшивки.
    /// </summary>
    [JsonPropertyName ("barcode")]
    [XmlAttribute ("barcode")]
    [DisplayName ("Метка")]
    [Description ("Штрих-код или радиометка (необязательно)")]
    public string? BindingBarcode { get; set; }

    /// <summary>
    /// Входящие в подписку номера должны существовать.
    /// </summary>
    [JsonPropertyName ("issue-must-exust")]
    [XmlAttribute ("issueMustExist")]
    [DisplayName ("Номера должны существовать")]
    [Description ("Входящие в подшивку номера журналов должны существовать?")]
    public bool IssueMustExist { get; set; }

    /// <summary>
    /// Входящие в подписку экземпляры должны существовать.
    /// </summary>
    [JsonPropertyName ("exemplar-must-exist")]
    [XmlAttribute ("exemplarMustExist")]
    [DisplayName ("Экземпляры должны существовать")]
    [Description ("Входящие в подшивку экземпляры должны существовать?")]
    public bool ExemplarMustExist { get; set; }

    #endregion

    #region Public methods

    /// <summary>
    /// Формирование шифра документа для указанного выпуска.
    /// </summary>
    [Pure]
    public string BuildIndex
        (
            string issueNumber
        )
    {
        Sure.NotNullNorEmpty (issueNumber);

        var result = string.IsNullOrEmpty (VolumeNumber)
            ? $"{MagazineIndex}/{Year}/{issueNumber}"
            : $"{MagazineIndex}/{Year}/{VolumeNumber}/{issueNumber}";

        return result;
    }

    #endregion

    #region IVerifiable members

    /// <inheritdoc cref="IVerifiable.Verify"/>
    [Pure]
    public bool Verify
        (
            bool throwOnError
        )
    {
        var verifier = new Verifier<BindingSpecification> (this, throwOnError);

        // номер тома и описание могут быть пустыми, это не ошибка
        // остальные элементы должны быть непустыми

        verifier
            .NotNullNorEmpty (MagazineIndex)
            .NotNullNorEmpty (Year)
            .NotNullNorEmpty (IssueNumbers)
            .NotNullNorEmpty (Place)
            .NotNullNorEmpty (BindingNumber)
            .NotNullNorEmpty (Inventory)
            .NotNullNorEmpty (Complect);

        return verifier.Result;
    }

    #endregion
}
